package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author LEO
 * @Date 2021年12月12日 23:53
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 1.在缓存中存储一个num 的初始值为0
     * 2.利用缓存的工具类StringRedisTemplate获取到当前的num值
     * 3.如果num不为空 ，则需要对当前进行+1操作
     * 4，如果Num为空，则返回即可
     */
    @Override
    public  void testLock() throws InterruptedException {

        // 使用redisson
       RLock lock= redissonClient.getLock("lock");
       //1. 最基本方式
//       lock.lock(10,TimeUnit.SECONDS);
//            // 处理业务
//            String num = redisTemplate.opsForValue().get("num");
//            if (StringUtils.isEmpty(num)){
//                return;
//            }
//            //3.如果num不为空 ，则需要对当前进行+1操作
//            int numValue=Integer.parseInt(num);
//            //写会缓存
//            redisTemplate.opsForValue().set("num", String.valueOf(++numValue));
//            //释放锁
//        lock.unlock();

        //2. tryLock()   第一个参数： 尝试加锁，最多等待100s        第二个参数 ：释放时间  上锁以后10s后自动解锁
//        boolean res = lock.tryLock(100,10,TimeUnit.SECONDS);
//        if (res){
//            try {
//                //上锁成功
//                // 处理业务
//                String num = redisTemplate.opsForValue().get("num");
//                if (StringUtils.isEmpty(num)){
//                    return;
//                }
//                //3.如果num不为空 ，则需要对当前进行+1操作
//                int numValue=Integer.parseInt(num);
//                //写会缓存
//                redisTemplate.opsForValue().set("num", String.valueOf(++numValue));
//            } finally {
//                    lock.unlock();
//            }
//        }

        // 3. lock.lockAsync()  不可行
//        lock.lockAsync();
//        //上锁成功
//        // 处理业务
//        String num = redisTemplate.opsForValue().get("num");
//        if (StringUtils.isEmpty(num)){
//            return;
//        }
//        //3.如果num不为空 ，则需要对当前进行+1操作
//        int numValue=Integer.parseInt(num);
//        //写会缓存
//        redisTemplate.opsForValue().set("num", String.valueOf(++numValue));
//        lock.unlockAsync();








        //1.测试本地锁
//    @Override
//    public   void testLock() {
//        //最基本方式   使用setnx 命令 setnx lock ok
//       // Boolean flag = redisTemplate.opsForValue().setIfAbsent("lock", "ok");
//
//        //使用setex 命令  setex key timeOut value
//       // Boolean flag = redisTemplate.opsForValue().setIfAbsent("lock", "ok", 5L, TimeUnit.SECONDS);
//
//        // 2.使用uuid 防止误删锁
//        String uuid= UUID.randomUUID().toString();
//        Boolean flag = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 5L, TimeUnit.SECONDS);
//        if (flag){
//            //如果flag为true ,获取到锁 处理业务
//            String num = redisTemplate.opsForValue().get("num");
//            if (StringUtils.isEmpty(num)){
//                return;
//            }
//            //3.如果num不为空 ，则需要对当前进行+1操作
//            int numValue=Integer.parseInt(num);
//            //写会缓存
//            redisTemplate.opsForValue().set("num", String.valueOf(++numValue));
//
////            // 判断是否是同一把锁   如果缓存中的uuid 与当前uuid 一致，则删除，否则不删
////            if (redisTemplate.opsForValue().get("lock").equals(uuid)){
////                //释放锁
////                redisTemplate.delete("lock");
////            }
//
//           3. Redis + Lua 方式
//            //定义一个Lua脚本：
//            /**
//             * 					if redis.call("get",KEYS[1]) == ARGV[1]
//             * 					then
//             * 						return redis.call("del",KEYS[1])
//             * 					else
//             * 						return 0
//             * 					end
//             */
//            String script="if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
//            //创建对象
//            DefaultRedisScript redisScript = new DefaultRedisScript<>();
//            // 设置lua 脚本
//            redisScript.setScriptText(script);
//            redisScript.setResultType(Long.class);
//            // redis 调用lua脚本
//            redisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);
//        }else {
//            //没有获取到锁
//            try {
//                Thread.sleep(500);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            //自旋
//            testLock();
//        }
//

    }



//读写锁互斥校验
    //读锁
    @Override
    public String readLock() {
        RReadWriteLock readWriteLock= redissonClient.getReadWriteLock("anyRWrite");
        //上锁  10s自动解锁
        readWriteLock.readLock().lock(10,TimeUnit.SECONDS);
        //从缓存中读取数据
        String msg = redisTemplate.opsForValue().get("msg");
        return msg;
    }

    //写锁
    @Override
    public String writeLock() {
        RReadWriteLock readWriteLock= redissonClient.getReadWriteLock("anyRWrite");
        //上锁  10s自动解锁
        readWriteLock.writeLock().lock(10,TimeUnit.SECONDS);
        //直接将内容写入缓存
        String uuid = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set("msg",uuid);
        //返回数据
        return "写入完成"+uuid;
    }
}
